package threadpoolnio.client;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Scanner;

/**
 * @author ：xx
 * @date ：Created in 2020/3/12 17:57
 * @description：
 * @modified By：
 */
public class NIOClient{
    private SocketChannel socketChannel = null;
    private String ip = null;
    private int port;
    ByteBuffer buff = ByteBuffer.allocate(1024);

    public NIOClient(String ip, int port) {
            this.ip = "127.0.0.1";
            this.port = 9999;
        try {
            connection(ip,port);

        } catch (IOException e) {
            System.out.println("连接服务器失败"+e.getMessage());
        }
    }


    public void connection(String ip, int port) throws IOException {
        socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
        socketChannel.connect(new InetSocketAddress(ip, port));
    }

    public void sendFile(String filepath) {
        FileChannel fileChannel = null;
        try {
            if(socketChannel==null||!socketChannel.isConnected()||!socketChannel.isOpen())
                connection(ip,port);
            if (socketChannel != null && socketChannel.finishConnect()) {
                if (filepath != null && filepath.length() > 0) {
                    File file = new File(filepath);
                    //获取文件通道
                    fileChannel = new FileInputStream(file).getChannel();
                    int count = -1;
//                    socketChannel.write(ByteBuffer.wrap(("1"+file.getName()+":").getBytes("GBK")));
                    // 设置消息头写入缓冲区
                    boolean isHeader = true;
                    while (fileChannel.position() < fileChannel.size()) {
                        //每次重新开一个buff
                        buff=ByteBuffer.allocate(1024);
                        //不要在里面打印，会造成界面阻塞
//                        System.out.println("已读取：" + fileChannel.position() + "，总大小:" + fileChannel.size());
                        if (isHeader) {
                            // 设置是否是文件头
                            buff.putInt(1);
                            // 写入文件名长度到帧头缓冲区 int为4字节
                            buff.putInt(file.getName().length());
//                            // 写入文件文件大小到帧头缓冲区
                            buff.putLong(fileChannel.size());
                            // 写入文件名到帧头缓冲区
                            buff.put(file.getName().getBytes("utf-8"));
                            isHeader = false;
                        } else {
                            buff.putInt(2);
                        }
                        //文件头结束，开始往buff里面放文件数据
                        count=fileChannel.read(buff);
                        if(count<=0)
                            break;
//                        while ((count = ) >0) {
                        buff.flip();
                        //把当前的缓冲区中数据写到网络通道里面
                        while (buff.hasRemaining()) {
                            socketChannel.write(buff);
                            //加上一个换行符
//                            socketChannel.write(ByteBuffer.wrap("\r\n".getBytes()));
                        }
                        buff.clear();
                    }
//                    System.out.println("发送数据完成,已读取：" + fileChannel.position() + "，总大小:" + fileChannel.size());
                    //关闭输出，否则服务端一直读不到-1
                    socketChannel.shutdownOutput();
                    count=-1;
                    buff.clear();
                    //获取服务端回发成功消息
                    //通道的好处，即可以写数据，也可以读数据 1个通道
                    //BIO 里面是通getInputStream  getOutputStream 2个流
                    while ((count=socketChannel.read(buff))!=-1){
                        if(count>0){
                            System.out.println("============服务端消息===============");
                            System.out.println(new String(buff.array(),0,count, "GBK"));
                        }
                        buff.clear();
                    }
//                    System.out.println("=====发送文件已结束，发送成功!===========");
                    close();

                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fileChannel != null)
                    fileChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void sendMsg(String msg) {
        try {
            if(socketChannel==null||!socketChannel.isConnected()||!socketChannel.isOpen())
                connection(ip,port);
            if (socketChannel != null && socketChannel.finishConnect()) {
                if (msg != null && msg.length() > 0) {
//                    socketChannel.write(ByteBuffer.wrap("0".getBytes("GBK")));
                    buff.clear();
                    //向缓冲区写数据
                    //0代码是文本数据，放在buff头部，4字节
                    buff.putInt(0);
                    buff.put(msg.getBytes("GBK"));
                    buff.flip();
                    while (buff.hasRemaining()) {
                        socketChannel.write(buff);
                        //加上一个换行符
//                        socketChannel.write(ByteBuffer.wrap("\r\n".getBytes()));
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void close() {
        try {
            if (socketChannel != null)
                socketChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        NIOClient client = new NIOClient("127.0.0.1", 9999);
        client.sendFile("D:\\javawork\\netdev\\test.txt");
        client.close();
    }
}
